/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */

package pardal.core;

import java.util.ArrayList;
import weka.core.Attribute;
import weka.core.Instances;

/**
 *
 * @author Valdigleis
 */
public abstract class ArffManipulationBase {
    
    //Lista de todos os nós da hierárquia.
    private ArrayList<Node> nodes;
    //Altura maxima da árvore
    private int height;
    
    private Instances instances;

    public ArffManipulationBase(Instances instances) {
        this.instances = instances;
        this.nodes = new ArrayList<>();
        discoveryNodes();
    }
    
    /**
     * Método que descobre todos os nós da hierárquia.
     */
    private void discoveryNodes(){
        //Inicializando todos os nós da hierárquia.
        Attribute attribute = this.instances.attribute(this.instances.numAttributes()-1);
        for (int i = 0; i < attribute.numValues(); i++) {
            Node newNode = new Node(attribute.value(i));
            this.nodes.add(newNode);
        }
        //calcula a altura do node mais alto da hierárquia.
        calcHeightMax();
        //Atribui o pai e os filhos de cada node.
        for (int i = 0; i < attribute.numValues(); i++) {
            setFatherInNodo(this.nodes.get(i));
            setSonsInNodo(this.nodes.get(i));
        }
    }
    
    /**
     * Método que seta o pai de um determiando node.
     * @param node - Nó que terá o pai setado.
     */
    private void setFatherInNodo(Node node){
        if(node.getLevel() == 0){
            node.setFather(node.NO_FATHER);
        }else{
            ArrayList<String> labels = getLabelofNodeForLevel(node.getLevel()-1);
            for(int i = 0; i < labels.size(); i++){
                if(node.getLabel().contains(labels.get(i))){
                    node.setFather(labels.get(i));
                }
            }
        }
    }
    
    /**
     * Método que seta todos os filhos de um determiando node.
     * @param node - Nó que terá o pai setado.
     */
    private void setSonsInNodo(Node node){
        ArrayList<String> sons = new ArrayList<>();
        if(node.getLevel() == this.height){
            node.setSons(sons);
        }else{
            ArrayList<String> labels = getLabelofNodeForLevel(node.getLevel()+1);
            for(int i = 0; i < labels.size(); i++){
                if(labels.get(i).contains(node.getLabel())){
                    String son = labels.get(i);
                    sons.add(son);
                }
            }
            node.setSons(sons);
        }
    }
    
    /**
     * Método que pega todos os labels dos nodes de um mesmo level da hierárquia.
     * 
     * @param level - O número do level que se deseje pegar os nodes.
     * @return nodesLocal - A lista com os labels dos nós do level requesitado..
     */
    private ArrayList<String> getLabelofNodeForLevel(int level){
        ArrayList<String> nodesLocal = new ArrayList<>();
        for (int i = 0; i < this.nodes.size(); i++) {
            if(this.nodes.get(i).getLevel() == level){
                String newNode = this.nodes.get(i).getLabel();
                nodesLocal.add(newNode);
            }
        }
        return nodesLocal;
    }
    
    /**
     * Método que encontra a altura do node mais alto da árvore.
     */
    private void calcHeightMax(){
        int max = 0;
        for(int i = 0; i < this.nodes.size(); i++){
            if(this.nodes.get(i).getLevel() > max){
                max = this.nodes.get(i).getLevel();
            }
        }
        this.height = max;
    }
    
    /**
     * Verifica se o node é uma folha.
     * 
     * @param classe - Label do Node
     * @return true/false - resposta se é ou não uma folha.
     */
    public boolean nodeIsLeaf(String classe){
        int index = 0;
        for(int i = 0; i < this.nodes.size(); i++){
            if(this.nodes.get(i).getLabel().equals(classe)){
                index = i;
                break;
            }
        }
        if(this.nodes.get(index).getSons().isEmpty() || this.nodes.get(index).getSons() == null){
            return true;
        }else{
            return false;
        }
    }
    
    public ArrayList<Node> getNodes() {
        return nodes;
    }

    public void setNodes(ArrayList<Node> nodes) {
        this.nodes = nodes;
    }

    public int getHeight() {
        return height;
    }

    public void setHeight(int height) {
        this.height = height;
    }

    public Instances getInstances() {
        return instances;
    }

    public void setInstances(Instances instances) {
        this.instances = instances;
    }
    
}
